package com.sofa.permission.service.impl;

import com.sofa.api.dto.permission.UserRoleDTO;
import com.sofa.common.constants.LogConstants;
import com.sofa.common.constants.MqConstants;
import com.sofa.common.constants.PermissionConstans;
import com.sofa.common.context.BaseContext;
import com.sofa.common.domain.OperationLogs;
import com.sofa.common.exception.*;
import com.sofa.common.utils.OperationLogDetailUtils;
import com.sofa.common.utils.RabbitMqHelper;
import com.sofa.permission.domain.po.Roles;
import com.sofa.permission.domain.po.UserRoles;
import com.sofa.permission.mapper.UserRolesMapper;
import com.sofa.permission.service.IRolesService;
import com.sofa.permission.service.IUserRolesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户-角色关系表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-06-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserRolesServiceImpl extends ServiceImpl<UserRolesMapper, UserRoles> implements IUserRolesService {

    private final IRolesService rolesService;
    private final RabbitMqHelper rabbitMqHelper;
    //根据角色获取角色id
    private static Map<String, Integer> roleMap = new HashMap<>(256);
    //根据角色id获取角色
    private static Map<Integer, String> userCodeMap = new HashMap<>(256);

    //绑定默认角色
    @Override
    @Transactional
    public Boolean bindDefaultRole(Long userId) {
        if (userId == null) {
            throw new BadRequestException("用户ID不能为空");
        }

        // 检查是否已经绑定角色
        UserRoles userRole = this.lambdaQuery()
                .select(UserRoles::getId)
                .eq(UserRoles::getUserId, userId)
                .one();

        if (userRole != null && userRole.getId() != null) {
            throw new CommonException("用户已绑定角色");
        }


        // 获取默认角色（普通用户）
        Integer roleId = roleMap.get(PermissionConstans.USER);//先尝试从本地Map中获取
        if (roleId == null) {
            Roles role = rolesService.lambdaQuery().select(Roles::getId).eq(Roles::getRoleCode, PermissionConstans.USER).one();
            if (role == null) {
                throw new RoleNotExitsException("角色不存在");
            }
            roleId = role.getId();
            roleMap.put(PermissionConstans.USER, roleId);
            userCodeMap.put(roleId, PermissionConstans.USER);
        }

        // 绑定角色
        userRole = new UserRoles();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);
        save(userRole);

//        throw new RuntimeException("测试seata分布式事务的回滚");
//        // 发送消息
        try {
            OperationLogs logs = new OperationLogs();
            logs.setUserId(userId);
            logs.setAction(LogConstants.BIND_DEFAULT_ROLE);
            logs.setIp(InetAddress.getLocalHost().getHostAddress());
            String details = OperationLogDetailUtils.generateInsertLog(userRole);
            logs.setDetail("用户绑定默认权限信息:" + details);
            rabbitMqHelper.sendMessage(MqConstants.Exchange.SOFA_LOG_EXCHANGE, MqConstants.RoutingKey.SOFA_LOG_OPERATION, logs);
        } catch (UnknownHostException e) {
            throw new MqMessageSendException("权限绑定消息发送失败");
        }
        return true;
    }

    //根据id获取用户角色
    @Override
    public String getUserRoleCode(Long userId) {
        if (userId == null) {
            throw new BadRequestException("用户ID不能为空");
        }
        // 检查是否已经绑定角色
        UserRoles userRoles = this.lambdaQuery()
                .select(UserRoles::getRoleId)
                .eq(UserRoles::getUserId, userId)
                .one();
        if(userRoles == null || userRoles.getRoleId() == null){
            throw new CommonException("用户未绑定角色");
        }
        // 根据roleId获取用户角色
        Integer roleId = userRoles.getRoleId();
        String roleCode = userCodeMap.get(roleId);
        if(roleCode == null){
            Roles role = rolesService.lambdaQuery().select(Roles::getRoleCode).eq(Roles::getId, roleId).one();
            if(role == null){
                throw new RoleNotExitsException("角色不存在");
            }
            roleCode = role.getRoleCode();
            roleMap.put(roleCode, roleId);
            userCodeMap.put(roleId, roleCode);
        }
        log.info("当前用户角色:{}", roleCode);
        return roleCode;
    }

    //根据角色获取用户id列表
    @Override
    public List<Long> getUserIdsByRolesCode(String roleCode) {
        if (roleCode == null) {
            throw new BadRequestException("角色不能为空");
        }
        //根据角色获取角色id
        Integer roleId = roleMap.get(roleCode);
        if(roleId == null){
            Roles role = rolesService.lambdaQuery().select(Roles::getId).eq(Roles::getRoleCode, roleCode).one();
            if(role == null){
                throw new RoleNotExitsException("角色不存在");
            }
            roleId = role.getId();
            roleMap.put(roleCode, roleId);
            userCodeMap.put(roleId, roleCode);
        }

        //根据角色id获取用户id列表
        List<Long> userIds = this.lambdaQuery()
                .select(UserRoles::getUserId)
                .eq(UserRoles::getRoleId, roleId)
                .list()
                .stream()
                .map(UserRoles::getUserId)
                .collect(Collectors.toList());

        return userIds;
    }

    @Override
    public Boolean upgradeToAdmin(Long userId) {
        log.info("进入 upgradeToAdmin，收到 userId: {}", userId);
        if(userId == null){
            throw new BadRequestException("用户ID不能为空");
        }
        //用户权限校验(用户模块已经校验过了,这里再次校验一次)
        Long currentId = BaseContext.getCurrentId();
        log.info("当前用户id:{}", currentId);
        String userRoleCode = this.getUserRoleCode(currentId);
        if (!userRoleCode.equals(PermissionConstans.SUPER_ADMIN)) {
            throw new PermissionDeniedException("权限不足");
        }

        //更新user_roles表
        //根据角色获取角色id
        Integer roleId = roleMap.get(PermissionConstans.ADMIN);
        if(roleId == null){
            Roles role = rolesService.lambdaQuery().select(Roles::getId).eq(Roles::getRoleCode, PermissionConstans.ADMIN).one();
            if(role == null){
                throw new RoleNotExitsException("角色不存在");
            }
            roleId = role.getId();
            roleMap.put(PermissionConstans.ADMIN, roleId);
            userCodeMap.put(roleId, PermissionConstans.ADMIN);
        }
        this.lambdaUpdate()
                .eq(UserRoles::getUserId, userId)
                .set(UserRoles::getRoleId, roleId)
                .update();

        //发送日志消息
        try {
            OperationLogs logs = new OperationLogs();
            logs.setUserId(currentId);
            logs.setAction(LogConstants.UPGRADE_TO_ADMIN);
            logs.setIp(InetAddress.getLocalHost().getHostAddress());
            logs.setDetail("用户" + userId + "被升级为管理员");
            rabbitMqHelper.sendMessage(MqConstants.Exchange.SOFA_LOG_EXCHANGE, MqConstants.RoutingKey.SOFA_LOG_OPERATION, logs);
        } catch (UnknownHostException e) {
            throw new MqMessageSendException("权限升级消息发送失败");
        }
        return true;
    }

    @Override
    public Boolean downgradeToUser(Long userId) {
        if(userId == null){
            throw new BadRequestException("用户ID不能为空");
        }

        //获取当前用户id
        Long currentId = BaseContext.getCurrentId();
        String userRoleCode = this.getUserRoleCode(currentId);
        if (!userRoleCode.equals(PermissionConstans.SUPER_ADMIN)) {
            throw new PermissionDeniedException("权限不足");
        }

        //更新user_roles表
        //根据角色获取角色id
        Integer roleId = roleMap.get(PermissionConstans.USER);
        if(roleId == null){
            Roles role = rolesService.lambdaQuery().select(Roles::getId).eq(Roles::getRoleCode, PermissionConstans.USER).one();
            if(role == null){
                throw new RoleNotExitsException("角色不存在");
            }
            roleId = role.getId();
            roleMap.put(PermissionConstans.USER, roleId);
            userCodeMap.put(roleId, PermissionConstans.USER);
        }
        //更新user_roles表
        this.lambdaUpdate()
                .eq(UserRoles::getUserId, userId)
                .set(UserRoles::getRoleId, roleId)
                .update();

        //发送日志消息
        try {
            OperationLogs logs = new OperationLogs();
            logs.setUserId(currentId);
            logs.setAction(LogConstants.DOWNGRADE_TO_USER);
            logs.setIp(InetAddress.getLocalHost().getHostAddress());
            logs.setDetail("用户" + userId + "被降级为普通用户");
            rabbitMqHelper.sendMessage(MqConstants.Exchange.SOFA_LOG_EXCHANGE, MqConstants.RoutingKey.SOFA_LOG_OPERATION, logs);
        } catch (UnknownHostException e) {
            throw new MqMessageSendException("权限升级消息发送失败");
        }
        return true;
    }

    @Override
    public List<UserRoleDTO> getUserRoleByUserIds(List<Long> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return Collections.emptyList();
        }
        //这里想不到其他高性能方法,只能在mapper层关联两个表了
        return baseMapper.selectUserRoleCodes(userIds);
    }


}
